#include<linux/module.h>
#include<linux/moduleparam.h>

struct semahore sema;//定义信号量

int demo_count = 0;
/*
    
    DECLARE_MUTEX(name)定义一个名为name的信号量并初始化为1
	DECLARE_MUTEX_LOCKED(name)定义一个名为name的信号量并初始化为0
	
	信号量的一般的使用
	DECLARE_MUTEX(mount_sem);//定义信号量
	down(&mount_sem);//获得信号量，保护临界区
	. . .
	critical section //临界区
	. . .
	up(&mount_sem);  //释放信号量
 */
 
 /*
	读写锁
	1.定义和初始化
		struct rw_semahore rw_sema;读写锁，允许N个进程读,一个进程写
		
		DECLARE_RWSEM(name)	
		声明名为name的读写信号量，并初始化它。
		
		void init_rwsem(struct rw_semaphore *sem);	
		对读写信号量sem进行初始化。
		
	2.读信号量获得
		void down_read(struct rw_semaphore *sem);	
		读者用来获取sem，若没获得时，则调用者睡眠等待。
		
		int down_read_trylock(struct rw_semaphore *sem);	
		读者尝试获取sem，如果获得返回1，如果没有获得返回0。可在中断上下文使用。
	
	3.读信号量获得
		void up_read(struct rw_semaphore *sem);	读者释放sem。
	
	4.写信号获得
		void down_write(struct rw_semaphore *sem);	
		写者用来获取sem，若没获得时，则调用者睡眠等待。
		
		int down_write_trylock(struct rw_semaphore *sem);
		写者尝试获取sem，如果获得返回1，如果没有获得返回0。可在中断上下文使用
		
	5.写信号释放
		void up_write(struct rw_semaphore *sem);	写者释放sem。
	
	6.降级
	void downgrade_write(struct rw_semaphore *sem);	把写者降级为读者。
	
	
	读写锁的一般使用
		rw_semaphore rw_sem;   //定义读写锁
		init_rwsem(&rw_sem);   //初始化
		
		//读时获得信号量
		down_read(&rw_sem);
		...                    //临界资源
		up_read(&rw_sem);
		
		//写时获得信号量
		down_write(&rw_sem);
		...                    //临界资源
		up_write(&rw_sem);
  */
 


int demoOpen(struct inode *p,struct file *f)
{
	printk(KERN_EMERG"demoOpen\r\n");
	/*
		也可以在open中获得信号量,
		在release中释放信号量
		
		这样整个设备就只能被一个进程打开
		
		本demo可以被多个进程打开 只不过保护了临界区只被一个进程打开
	
	 */
	return 0;
}

ssize_t demoWrite(struct file *f,const char __user *u,size_t s,loff_t *l)
{	
	
	down(&sema);
	/*	获得信号量
		down(struct semahore *sema)
		会导致睡眠,不能在中断上下文使用,因down而进入睡眠的进程不能被信号打断
		
		down_interruptible()
		会导致睡眠,因down_interruptible()而进入睡眠的进程能被信号打断，
		信号也会导致该函数返回，这是该函数返回值非0
		
		int down_trylock(struct semaphore *sem);
		不会导致调用者睡眠
		改函数尝试获得信号量sem,如果能够立即获得,他就获得该信号量返回0,
		否则,返回非0值,可以在中断上下文使用。
	 */
	if(demo_count)
	{
		up(&sema);
		/*
			释放信号量
			void up(struct semaphore *sem)
			该函数释放信号量sem，唤醒等待者
		 */
		return -EBUSY;
	}
	++demo_count;
	//sode
	up(&sema);
	printk(KERN_EMERG"--dmeowrite-\n");  
	return 0;
}

int demoRelease(struct inode *inode,struct file *file)
{
	down(&sema);
	--xxx_count;
    up(&sema);
	printk(KERN_EMERG"---");
	return 0;
}
int charDemoInit(void)
{  
	xxx_fops->open =demoOpen;
	
	xxx_fops->write = demoWrite;
	
	xxx_fops->release = demoRelease;
	
    sema_init(&sema,1);
	/*
		其他的初始化函数
		init_MUTEX(struct semahore *sema); 
		相当于sema_init(&sema,1);将sem的值设为1,初始化一个互斥锁,表示空闲
		
		init_MUTEX_LOCKED(struct semahore *sema);
		相当于sema_init(&sema,0);将sem的值设为1,表示资源忙	
		
		DECLARE_MUTEX(name)定义一个名为name的信号量并初始化为1
		DECLARE_MUTEX_LOCKED(name)定义一个名为name的信号量并初始化为0
	 */
	
	return 0;
}

void __exit charDemoExit(void)
{   
	return;
}

module_init(charDemoInit);//insmod ***.ko
module_exit(charDemoExit);//rmmod ***.ko
MODULE_LICENSE("GPL");